package com.jsg.sl651.message.parser;

import com.jsg.sl651.constant.EncodingElementIdentifier;
import com.jsg.sl651.entity.data.Element;
import com.jsg.sl651.enums.CommunicationMessageType;
import com.jsg.sl651.exception.ParserDataElementException;
import com.jsg.sl651.exception.ParserRegisterException;

import java.util.HashMap;

/**
 * 解析器工厂【保管所有的解析器，以及解析器实例，可以通过这个类注册解析器】
 */
public final class ParserFactory {

    private static final HashMap<Class<? extends Parser<?>>, Parser<?>> PARSER_MAP = new HashMap<>();

    static {
        // todo 注册一些默认的解析器
    }


    /**
     * 注册解析器到工厂中。
     *
     * <p>方法核心</p>
     * <ul>
     *     <li>通过传入的解析器类创建实例，并将其存储在解析器映射表中。</li>
     *     <li>如果实例化过程中发生异常，抛出 ParserRegisterException 异常。</li>
     * </ul>
     *
     * @param clazz 要注册的解析器类，必须是 {@link Parser} 的子类
     * @throws ParserRegisterException 如果解析器注册失败时抛出的异常，包含失败原因
     */
    private static void registerParser(Class<? extends Parser<?>> clazz) {
        try {
            PARSER_MAP.put(clazz, clazz.newInstance());
        } catch (Exception e) {
            throw new ParserRegisterException("解析器 {} 注册失败：{}", clazz.getName(), e.getMessage());
        }
    }


    /**
     * 使用指定的解析器类解析字节数组为数据对象。
     *
     * <p>方法核心</p>
     * <ul>
     *     <li>首先尝试从解析器映射表中获取解析器实例。</li>
     *     <li>如果解析器实例不存在，则注册该解析器类并再次尝试获取。</li>
     *     <li>使用获取到的解析器实例解析字节数组。</li>
     * </ul>
     *
     * @param encodingElement 解析相关定义
     * @param type  通信消息类型，枚举值 {@link CommunicationMessageType}
     * @param bytes 待解析的字节数组
     * @return 解析成功后生成的数据对象 {@link Element}
     * @throws ParserDataElementException 如果解析失败时抛出的异常
     * @throws ParserRegisterException 如果解析器注册失败时抛出的异常
     */
    public static Element<?> parser(EncodingElementIdentifier.EncodingElement encodingElement,CommunicationMessageType type , byte[] bytes) {
        Class<? extends Parser<?>> clazz = encodingElement.getParser();
        Parser<?> parser = PARSER_MAP.get(clazz);
        if (parser == null) {
            synchronized (ParserFactory.class) {
                if (PARSER_MAP.get(clazz) == null) {
                    registerParser(clazz);
                    parser = PARSER_MAP.get(clazz);
                }
            }
        }
        if (parser == null) {
            throw new ParserRegisterException("解析器 {} 注册失败：{}", clazz.getName(), "解析器实例为空");
        }
        return parser.parser(encodingElement, type, bytes);
    }

}
